﻿/* --- Copyright (c) notice NevoWeb ---
  Copyright (c) 2008 SARL NevoWeb.  www.nevoweb.com. All rights are reserved.
 Author: D.C.Lee
 ------------------------------------------------------------------------
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 DEALINGS IN THE SOFTWARE.
 ------------------------------------------------------------------------
 This copyright notice may NOT be removed, obscured or modified without written consent from the author.
 --- End copyright notice --- 
*/

using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Web;
using System.Net;
using System.IO;
using System.Collections.Specialized;
using System.Xml;
using NEvoWeb.Modules.NB_Store;

namespace Nevoweb.NBrightStore.Gateway
{

    public class EWay : GatewayInterface
    {

        public string _AuthCode = string.Empty;
        public string _ResponseCode = string.Empty;
        public string _ReturnAmount = string.Empty;
        public string _TrxnNumber = string.Empty;
        public string _TrxnStatus = string.Empty;
        public string _MerchnatOption1 = string.Empty;
        public string _MerchnatOption2 = string.Empty;
        public string _MerchnatOption3 = string.Empty;
        public string _ReferenceNumber = string.Empty;
        public string _ReferenceInvoice = string.Empty;
        public string _TrxnResponseMessage = string.Empty;
        public string _ErrorMessage = string.Empty;

        public override string GetButtonHtml(int PortalID, int OrderID, string Lang)
        {
            string strHTML = "";

            string gatewayParams = SharedFunctions.GetStoreSetting(PortalID, "eway.gateway", "None");

            if (!string.IsNullOrEmpty(gatewayParams))
            {
                //Move the xml format settings into the a hashtable so we can use it easily.
                var setParams = createSettingsTable(gatewayParams);

                //Build Html to display the payment button.
                strHTML = "<input type='image' name='ewaygateway' border='0' src='" + setParams["buttonimageurl"] + "' />";

            }

            return strHTML;
        }


        // ------------------------------------------------------------------------
        // Step Three: Auto Response from banking gateway.  ()
        // If the banking gateway supports Automatic response (A url is send to the store just after the users make the payment,
        // but before they click to return to the store) then this function deals with what needs to be done in NB_Store.
        // NOTE:
        // - Not all gateways support this, in which case the payment processing for NB_Store needs to be done in the "GetCompletedHtml" function.
        // ------------------------------------------------------------------------
        public override void AutoResponse(int PortalID, System.Web.HttpRequest Request)
        {
            // NOTE:  THIS METHOD HAS NOW BEEN REPLACED BY THE USE OF THE Nevoweb.NBrightStore.Gateway.ExampleGateway.NotifyProvider.
 
            // It will still work.  However if the payment provider requires a specific response, then in DNN6 the whole web page is also returned.
            // Using the Notify web handler avoids this.

            // In the case of E-Way I can't see any suport for this on the shared hosting?..So I've simply not implemented any processing.
            // Because no auto response is being triggered all store processing for the transaction will have to be done on return to the Store.

        }

        public override string GetCompletedHtml(int PortalID, int UserID, System.Web.HttpRequest Request)
        {
            SettingsController objSCtrl = new SettingsController();
            OrderController objOCtrl = new OrderController();
            ProductController objPCtrl = new ProductController();
            NB_Store_OrdersInfo objOInfo = default(NB_Store_OrdersInfo);
            NB_Store_SettingsTextInfo objSInfo = default(NB_Store_SettingsTextInfo);
            int ordID = -1;
            string rtnMsg = "";
            string AccessPaymentCode = string.Empty;

            //Get the order id back from the url.
            var strID = Request.QueryString["ordid"];
            SharedFunctions.UpdateLog("EWAY RETURNED ORDERID (ordid) = " + strID);

            //set rtnMsg to security warning message.
            objSInfo = objSCtrl.GetSettingsText(PortalID, "paymentSECURITY.text", SharedFunctions.GetCurrentCulture());
            rtnMsg = objSInfo.SettingText;
            if (int.TryParse(strID, out ordID))
            {
                objOInfo = objOCtrl.GetOrder(ordID);
                if ((objOInfo != null))
                {
                    //Here we make sure that the user  trying to view the order is the same as the user that placed the order.
                    //If this is not the case, then we want to display the security warning.

                    switch (Request.QueryString["ewayexit"].ToUpper())
                    {
                        case "CANCEL":
                            // check if order has already been processed
                            if (!objOInfo.OrderIsPlaced)
                            {
                                //check if order has already been cancelled
                                if (objOInfo.OrderStatusID != 30)
                                {
                                    //remove qty in trans
                                    objPCtrl.RemoveModelQtyTrans(objOInfo.OrderID);
                                    //set order status to cancelled
                                    objOInfo.OrderStatusID = 30;
                                    objOCtrl.UpdateObjOrder(objOInfo);
                                }
                                //set Cancel order message
                                objSInfo = objSCtrl.GetSettingsText(PortalID, "paymentFAIL.text", SharedFunctions.GetCurrentCulture());
                                rtnMsg = objSInfo.SettingText;

                            }
                            break;
                        case "RETURN":
                            // check if order has already been processed
                            if (!objOInfo.OrderIsPlaced)
                            {
                                if (Request.Form["AccessPaymentCode"] != null)
                                    AccessPaymentCode = Request.Form["AccessPaymentCode"].ToString(CultureInfo.InvariantCulture);

                                string gatewayParams = SharedFunctions.GetStoreSetting(PortalID, "eway.gateway", "None");

                                if (!string.IsNullOrEmpty(gatewayParams))
                                {
                                    //Move the xml format settings into the a hashtable so we can use it easily.
                                    var setParams = createSettingsTable(gatewayParams);

                                    //get the result of the transaction based on the unique payment code
                                    if (CheckAccessCode(PortalID, setParams, AccessPaymentCode))
                                    {
                                        if (_TrxnStatus.ToLower().Equals("true"))
                                        {
                                            //remove qty in trans
                                            objPCtrl.UpdateStockLevel(objOInfo.OrderID);
                                            //set order status to Payed
                                            objOInfo.OrderStatusID = 45;
                                            objOInfo.OrderNumber = objOInfo.PortalID.ToString("00") + "-" + UserID.ToString("0000#") + "-" + objOInfo.OrderID.ToString("0000#") + "-" + objOInfo.OrderDate.ToString("yyyyMMdd");
                                            objOInfo.OrderIsPlaced = true;
                                            objOInfo.PayType = "EWAY";
                                            objOCtrl.UpdateObjOrder(objOInfo);
                                            SharedFunctions.SendEmailToClient(objOInfo.PortalID, SharedFunctions.GetClientEmail(objOInfo.PortalID, objOInfo), objOInfo.OrderNumber, objOInfo, "paymentOK.email", SharedFunctions.GetCurrentCulture());
                                            SharedFunctions.SendEmailToManager(objOInfo.PortalID, objOInfo.OrderNumber, objOInfo, "paymentOK.email");
                                            //set completed order message
                                            objSInfo = objSCtrl.GetSettingsText(PortalID, "paymentOK.text", SharedFunctions.GetCurrentCulture());
                                        }
                                        else
                                        {
                                            //set Cancel order message
                                            objSInfo = objSCtrl.GetSettingsText(PortalID, "paymentFAIL.text", SharedFunctions.GetCurrentCulture());
                                        }
                                    }
                                    else
                                    {
                                        SharedFunctions.UpdateLog("EWAY FRAUD ");
                                    }
                                    rtnMsg = objSInfo.SettingText;
                                }
                            }
                            break;
                        default:
                            break;
                            // break
                    }

                    //Do Token Replacement
                    var objTR = new TokenStoreReplace(objOInfo, SharedFunctions.GetMerchantCulture(PortalID));
                    rtnMsg = objTR.DoTokenReplace(rtnMsg);
                }
            }
            return rtnMsg;
        }

        public override bool GetBankClick(int PortalID, System.Web.HttpRequest Request)
        {
            //test if button has been clicked
            if ((Request.Form["ewaygateway.x"] != null))
            {
                return true;
            }
            return false;
        }

        public override void SetBankRemotePost(int PortalID, int OrderID, string Lang, System.Web.HttpRequest Request)
        {
            // RemotePost class from NB_Store, this generates the re-direct html required.
            //test if e-way button has been clicked
            if (GetBankClick(PortalID, Request))
            {
                string gatewayParams = SharedFunctions.GetStoreSetting(PortalID, "eway.gateway", "None");

                if (!string.IsNullOrEmpty(gatewayParams))
                {
                    //Parse the gateway setttings into a Hashtable for easy access.
                    Hashtable setParams = createSettingsTable(gatewayParams);

                    var returnUrl = setParams["returnurl"] as string;
                    var cancelUrl = setParams["returncancelurl"] as string;
                    var ewayPostToUrl = setParams["PaymentGatewayAddr"] as string;

                    OrderController objOCtrl = new OrderController();
                    NB_Store_OrdersInfo oInfo = objOCtrl.GetOrder(OrderID);

                    if ((oInfo != null))
                    {

                        if (returnUrl != null)
                        {
                            returnUrl = returnUrl.Replace("[ORDERID]", oInfo.OrderID.ToString(""));
                        }
                        else
                        {
                            SharedFunctions.UpdateLog("EWAY ERROR = NULL return URL");
                            return;
                        }

                        if (cancelUrl != null)
                        {
                            cancelUrl = cancelUrl.Replace("[ORDERID]", oInfo.OrderID.ToString(""));
                        }
                        else
                        {
                            SharedFunctions.UpdateLog("EWAY ERROR = NULL cancel URL");
                            return;
                        }

                        // get cart to store return data
                        NB_Store_CartInfo objCInfo = CurrentCart.GetCurrentCart(PortalID);

                        // Get Remote Post class
                        var rPost = new RemotePost();

                        //update stock tranction in progress
                        ProductController objPCtrl = new ProductController();
                        objPCtrl.UpdateModelQtyTrans(oInfo.OrderID);

                        //set order status to redirect to bank
                        oInfo.OrderStatusID = 20;
                        objOCtrl.UpdateObjOrder(oInfo);

                        NB_Store_AddressInfo aInfo = objOCtrl.GetOrderAddress(oInfo.BillingAddressID);

                        
                        //----------------------------------------------------------------------------------------
                        // EWAY code to get response and URI from EWay 
                        //----------------------------------------------------------------------------------------

                        string resultXML = "";

                        string strPost = "CustomerID=" + setParams["CustomerID"];
                        strPost += Format("UserName", setParams["UserName"].ToString());
                        strPost += Format("Amount", oInfo.Total.ToString("0.00"));    //send amounts to the generator in DOLLAR FORM. ie 10.05
                        strPost += Format("Currency", setParams["Currency"].ToString());
                        strPost += Format("PageTitle", setParams["PageTitle"].ToString());
                        strPost += Format("PageDescription", setParams["PageDescription"].ToString());
                        strPost += Format("PageFooter", setParams["PageFooter"].ToString());
                        strPost += Format("Language", SharedFunctions.GetCurrentCulture().Substring(0,2).ToUpper());
                        strPost += Format("CompanyName", setParams["CompanyName"].ToString());
                        strPost += Format("CustomerFirstName", aInfo.AddressName);
                        strPost += Format("CustomerLastName", "");
                        strPost += Format("CustomerAddress", aInfo.Address1 + " " + aInfo.Address2);
                        strPost += Format("CustomerCity", aInfo.City);
                        strPost += Format("CustomerState", "");
                        strPost += Format("CustomerPostCode", aInfo.PostalCode );
                        strPost += Format("CustomerCountry", "");
                        strPost += Format("CustomerEmail", oInfo.Email);
                        strPost += Format("CustomerPhone", aInfo.Phone1);
                        strPost += Format("InvoiceDescription", setParams["InvoiceDescription"].ToString());
                        strPost += Format("CancelURL", cancelUrl);
                        strPost += Format("ReturnUrl", returnUrl);


                        strPost += Format("MerchantReference", setParams["MerchantReference"].ToString());
                        strPost += Format("MerchantInvoice", oInfo.OrderID.ToString(""));
                        strPost += Format("MerchantOption1", CurrentCart.GetCurrentCart(PortalID).CartID);
                        strPost += Format("MerchantOption2", setParams["MerchantOption2"].ToString());
                        strPost += Format("MerchantOption3", setParams["MerchantOption3"].ToString());
                        strPost += Format("PageBanner", setParams["PageBanner"].ToString());
                        strPost += Format("CompanyLogo", setParams["CompanyLogo"].ToString());
                        strPost += Format("ModifiableCustomerDetails", setParams["ModifiableCustomerDetails"].ToString());

                        if (ewayPostToUrl != null)
                        {
                            string url = ewayPostToUrl.TrimEnd('/') + "/" + "Request?" + strPost;

                            HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create(url);
                            objRequest.Method = WebRequestMethods.Http.Get;

                            try
                            {
                                HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();

                                //get the response from the transaction generate page
                                using (StreamReader sr = new StreamReader(objResponse.GetResponseStream()))
                                {
                                    resultXML = sr.ReadToEnd();
                                    // Close and clean up the StreamReader
                                    sr.Close();
                                }
                            }
                            catch (Exception ex)
                            {
                                SharedFunctions.UpdateLog("EWAY REQUEST URL = " + url);
                                objCInfo.BankHtmlRedirect = ex.Message;
                                CurrentCart.Save(objCInfo);
                                SharedFunctions.UpdateLog("EWAY ERROR = " + ex.Message);
                                return;
                            }
                        }

                        //parse the result message
                        TransactionRequestResult resultObj = ParseResults(resultXML);


                        if (resultObj.Result)
                        {
                            //redirect the user to the payment page
                            rPost.Url = resultObj.URI;
                        }
                        else
                        {
                            objCInfo.BankHtmlRedirect = resultObj.Error;
                            CurrentCart.Save(objCInfo);
                            SharedFunctions.UpdateLog("EWAY ERROR = " + resultObj.Error);
                            return;
                        }

                        //----------------------------------------------------------------------------------------
                        // EWAY Code End.
                        //----------------------------------------------------------------------------------------

                        var gatewayImg = SharedFunctions.GetStoreSetting(PortalID, "gateway.loadimage", "None");

                        objCInfo.BankHtmlRedirect = rPost.GetPostHtml(gatewayImg);
                        CurrentCart.Save(objCInfo);

                    }
                }
            }
        }

        public Hashtable createSettingsTable(string SettingsParams)
        {
            return SharedFunctions.ParseGateway(SettingsParams);
        }



        #region "private methods/classes"

        public class TransactionRequestResult
        {
            public bool Result;
            public string URI;
            public string Error;
        }


        /// <summary>
        /// Format the string needed to post to the Generate page
        /// </summary>
        /// <param name="fieldName">eWAY Parameter Name</param>
        /// <param name="value">Value of Parameter</param>
        /// <returns>Formated value for the URL</returns>
        private string Format(string fieldName, string value)
        {
            if (!string.IsNullOrEmpty(value))
                return "&" + fieldName + "=" + SharedFunctions.HTTPPOSTEncode(value);
            else
                return "";
        }

        /// <summary>
        /// Parse the result of the transaction request and save the appropriate fields in an object to be used later
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        private TransactionRequestResult ParseResults(string xml)
        {
            string _currentNode;
            StringReader _sr = new StringReader(xml);
            XmlTextReader _xtr = new XmlTextReader(_sr);
            _xtr.XmlResolver = null;
            _xtr.WhitespaceHandling = WhitespaceHandling.None;

            // get the root node
            _xtr.Read();

            TransactionRequestResult res = new TransactionRequestResult();

            if ((_xtr.NodeType == XmlNodeType.Element) && (_xtr.Name == "TransactionRequest"))
            {
                while (_xtr.Read())
                {
                    if ((_xtr.NodeType == XmlNodeType.Element) && (!_xtr.IsEmptyElement))
                    {
                        _currentNode = _xtr.Name;
                        _xtr.Read();
                        if (_xtr.NodeType == XmlNodeType.Text)
                        {
                            switch (_currentNode)
                            {
                                case "Result":
                                    res.Result = bool.Parse(_xtr.Value);
                                    break;

                                case "URI":
                                    res.URI = _xtr.Value;
                                    break;

                                case "Error":
                                    res.Error = _xtr.Value;
                                    break;
                            }
                        }
                    }
                }
            }

            return res;


        }


        /// <summary>
        /// Procedure to check the 64 character access payment code
        /// for security
        /// </summary>
        /// <param name="setParams"> </param>
        /// <param name="AccessPaymentCode">64 char code</param>
        /// <param name="PortalID"> </param>
        /// <returns>true if found; false if not found</returns>
        protected bool CheckAccessCode(int PortalID, Hashtable setParams, string AccessPaymentCode)
        {

                //POST to Payment gateway the access code returned
            string strPost = "CustomerID=" + setParams["CustomerID"];
                strPost += Format("AccessPaymentCode", AccessPaymentCode);
                strPost += Format("UserName", setParams["UserName"].ToString());

                string url = setParams["PaymentGatewayAddr"].ToString().TrimEnd('/') + "/" + "Result?" + strPost;

                HttpWebRequest objRequest = (HttpWebRequest) WebRequest.Create(url);
                objRequest.Method = WebRequestMethods.Http.Get;
                string resultXML = string.Empty;

                try
                {
                    HttpWebResponse objResponse = (HttpWebResponse) objRequest.GetResponse();

                    //get the response from the transaction generate page
                    using (StreamReader sr = new StreamReader(objResponse.GetResponseStream()))
                    {
                        resultXML = sr.ReadToEnd();
                        // Close and clean up the StreamReader
                        sr.Close();
                    }
                }
                catch (Exception ex)
                {
                    return false;
                }

                //parse the results save the values
                ParseAndSaveXMLResult(resultXML);

                return true;
        }


        /// <summary>
        /// Parse the XML Returned and save all the values to be displayed to user
        /// </summary>
        /// <param name="resultXML">XML of the transaction result</param>
        private void ParseAndSaveXMLResult(string resultXML)
        {
            string _currentNode;
            StringReader _sr = new StringReader(resultXML);
            XmlTextReader _xtr = new XmlTextReader(_sr);
            _xtr.XmlResolver = null;
            _xtr.WhitespaceHandling = WhitespaceHandling.None;

            // get the root node
            _xtr.Read();

            if ((_xtr.NodeType == XmlNodeType.Element) && (_xtr.Name == "TransactionResponse"))
            {
                while (_xtr.Read())
                {
                    if ((_xtr.NodeType == XmlNodeType.Element) && (!_xtr.IsEmptyElement))
                    {
                        _currentNode = _xtr.Name;
                        _xtr.Read();
                        if (_xtr.NodeType == XmlNodeType.Text)
                        {
                            switch (_currentNode)
                            {

                                case "AuthCode":
                                    _AuthCode = _xtr.Value;
                                    break;
                                case "ResponseCode":
                                    _ResponseCode = _xtr.Value;
                                    break;
                                case "ReturnAmount":
                                    _ReturnAmount = _xtr.Value;
                                    break;
                                case "TrxnStatus":
                                    _TrxnStatus = _xtr.Value;
                                    break;
                                case "TrxnNumber":
                                    _TrxnNumber = _xtr.Value;
                                    break;
                                case "MerchantOption1":
                                    _MerchnatOption1 = _xtr.Value;
                                    break;
                                case "MerchantOption2":
                                    _MerchnatOption2 = _xtr.Value;
                                    break;
                                case "MerchantOption3":
                                    _MerchnatOption3 = _xtr.Value;
                                    break;
                                case "MerchantInvoice":
                                    _ReferenceInvoice = _xtr.Value;
                                    break;
                                case "MerchantReference":
                                    _ReferenceNumber = _xtr.Value;
                                    break;

                                case "TrxnResponseMessage":
                                    _TrxnResponseMessage = _xtr.Value;
                                    break;
                                case "ErrorMessage":
                                    _ErrorMessage = _xtr.Value;
                                    break;

                            }
                        }
                    }
                }
            }
        }

        #endregion

    }

}